#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#include <unistd.h>
#include <iostream>
#include <synchapi.h>
#include <cstdlib>
#include <ctime>
using namespace std;

#define SHM_NAME "BUFFER"
static HANDLE Handle_Of_FileMap;
static HANDLE Handle_Of_Subprocess[6];
int Size_Of_Buffer = 6;

int Get_Time() //得到随机时间
{
    int digit;
    srand((unsigned)(time(NULL)));
    digit = rand() % 1000;
    return digit;
};

char Get_Content()
{
    char m = '0';
    int r = rand() % (9) + 0;
    return (char)(m + r);
};

struct Buffer //定义缓冲区
{
    char Buf[6][10];
    int Buffer_Head;
    int Buffer_End;
    int Buffer_Is_Empty;
};

struct Memory //定义进程通信的共享存储区
{
    struct Buffer buf;
};

HANDLE Make_Shared_Zone()
{
    HANDLE handleFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(struct Memory), SHM_NAME);
    if (handleFileMapping == NULL || handleFileMapping == INVALID_HANDLE_VALUE)
    {
        //  printf("FAIL:%d\n", GetLastError());
        printf("Failed to make shared zone!");
        return NULL;
    }
    if (handleFileMapping != INVALID_HANDLE_VALUE)
    {
        //把文件映射对象的一个视图映射到当前进程的地址空间，返回值为文件映射的起始地址
        LPVOID pData = MapViewOfFile(handleFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); //高32位，低32位，整个文件映射
        if (pData == NULL)
        {
            printf("Failed to make shared zone!\n", GetLastError());
            return NULL;
        }
        if (pData != NULL)
        {
            //将指定的存储空间清0
            ZeroMemory(pData, sizeof(struct Memory));
        }
        //在当前进程的地址空间中解除对一个文件映射对象的映射
        UnmapViewOfFile(pData);
    }
    return handleFileMapping;
};

void MakeSubProcess(int SubprocessID)
{
    char szFilename[MAX_PATH];
    char szCmdLine[MAX_PATH];
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    //获得当前可执行文件名，hModule为NULL返回当前可执行文件的路径名；存放给定模块的路径和文件名；缓冲区大小
    GetModuleFileName(NULL, szFilename, MAX_PATH);
    sprintf(szCmdLine, "\"%s\" %d", szFilename, SubprocessID);

    memset(&si, 0, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);

    //创建子进程
    BOOL bCreateOK = CreateProcess(szFilename, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
    //将新创建进程的句柄赋值给进程ID为subProID的子进程
    Handle_Of_Subprocess[SubprocessID] = pi.hProcess;
    return;
}

int main(int argc, char *argv[])
{
    int state = 0;
    int NextProcessIndex = 1;
    SYSTEMTIME time;

    if (argc > 1)
    {
        sscanf(argv[1], "%d", &state);
    }

    if (state == 0) //意为当前处于主进程段
    {
        cout << "MAIN PROCESS IS GOING!\n";     //程序当前运行在主进程段
        Handle_Of_FileMap = Make_Shared_Zone(); //创建各进程间文件共享区
        //映射视图
        HANDLE hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, SHM_NAME);
        if (hFileMapping == NULL)
        {
            printf("Failed to make shared zone Mapping!", GetLastError());
            return -1;
        }

        LPVOID pFile = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        if (pFile == NULL)
        {
            printf("Failed to make shared zone Mapping!%d\n", GetLastError());
            return 1;
        }
        else
        {
            struct Memory *SM = (struct Memory *)(pFile);
            SM->buf.Buffer_Head = 0;
            SM->buf.Buffer_End = 0;

            HANDLE Temp_Memory_Is_Empty = CreateSemaphore(NULL, 6, 6, "Memory_Is_Empty");
            HANDLE Temp_Memory_Is_Full = CreateSemaphore(NULL, 0, 6, "Memory_Is_Full");
            HANDLE Temp_Mutex = CreateMutex(NULL, FALSE, "Mutex");

            //取消文件映射
            UnmapViewOfFile(pFile);
            pFile = NULL;
        }
        CloseHandle(hFileMapping); //关闭映射

        while (NextProcessIndex <= 5)
        {
            MakeSubProcess(NextProcessIndex++);
        }

        for (int i = 1; i < 6; i++)
        {
            WaitForSingleObject(Handle_Of_Subprocess[i], INFINITE);
            CloseHandle(Handle_Of_Subprocess[i]);
            cout << "close" << i << endl;
        }

        printf("\nMAINPROCESS Finish!\n");
    }

    else if (state == 1 || state == 3) //意为当前处于生产者进程段
    {
        char con[10];
        int position;
        //映射视图
        HANDLE hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, SHM_NAME);
        if (hFileMapping == NULL)
        {
            printf("Producer Process Get Mapping Failed!");
            return -1;
        }
        LPVOID pFile = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        if (pFile == NULL)
        {
            printf("Producer Process Get Mapping Failed!");
            return -1;
        }
        else
        {
            // cout << state << "here" << endl;

            struct Memory *SM = (struct Memory *)(pFile);
            HANDLE Temp_Memory_Is_Empty = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Memory_Is_Empty");
            HANDLE Temp_Memory_Is_Full = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Memory_Is_Full");
            HANDLE Temp_Mutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "Mutex");

            for (int p = 0; p < 12; p++)
            {
                Sleep(Get_Time());
                WaitForSingleObject(Temp_Memory_Is_Empty, INFINITE);
                WaitForSingleObject(Temp_Mutex, INFINITE);

                for (int i = 0; i < 9; i++)
                    con[i] = Get_Content();
                con[9] = '\0';
                for (int i = 0; i < 10; i++)
                    SM->buf.Buf[SM->buf.Buffer_End][i] = con[i];
                // cout << state << "good" << endl;

                SM->buf.Buffer_End = (SM->buf.Buffer_End + 1) % Size_Of_Buffer;
                SM->buf.Buffer_Is_Empty = 0;

                GetSystemTime(&time);
                printf("%02d:%02d:%02d     ", time.wHour + 8, time.wMinute, time.wSecond);

                position = SM->buf.Buffer_End - SM->buf.Buffer_Head;
                if (position < 0)
                    position += 6;

                printf("%15dProducer---WRITING---%s---for#%d\t", state, con, p);
                cout << endl;
                for (int d = 0; d < 10; d++)
                    cout << " ";
                for (int i = SM->buf.Buffer_Head, j = 0; j < position; j++, i++)
                    cout << SM->buf.Buf[i % Size_Of_Buffer] << "  ";
                cout << endl;
                //cout << "Producer---" << state << "---WRITING---" << con<< "---for#" << p << endl;
                ReleaseMutex(Temp_Mutex);
                ReleaseSemaphore(Temp_Memory_Is_Full, 1, NULL);
            }
            UnmapViewOfFile(pFile);
            pFile = NULL;
        }

        CloseHandle(hFileMapping);
    }

    else if (state == 2 || state == 4 || state == 5) //意为当前处于消费者进程段
    {
        char con[10];
        int position;
        //映射视图
        //

        HANDLE hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, SHM_NAME);
        if (hFileMapping == NULL)
        {
            printf("Producer Process Get Mapping Failed!");
            return -1;
        }
        LPVOID pFile = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        if (pFile == NULL)
        {
            printf("Producer Process Get Mapping Failed!");
            return -1;
        }
        else
        {
            // cout << state << "there" << endl;
            struct Memory *SM = (struct Memory *)(pFile);
            HANDLE Temp_Memory_Is_Empty = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Memory_Is_Empty");
            HANDLE Temp_Memory_Is_Full = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Memory_Is_Full");
            HANDLE Temp_Mutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "Mutex");

            for (int p = 0; p < 8; p++)
            {
                Sleep(Get_Time());
                WaitForSingleObject(Temp_Memory_Is_Full, INFINITE);
                WaitForSingleObject(Temp_Mutex, INFINITE);

                for (int i = 0; i < 10; i++)
                    con[i] = SM->buf.Buf[SM->buf.Buffer_Head][i];

                SM->buf.Buffer_Head = (SM->buf.Buffer_Head + 1) % Size_Of_Buffer;
                if (SM->buf.Buffer_Head == SM->buf.Buffer_End)
                    SM->buf.Buffer_Is_Empty = 1;
                else
                    SM->buf.Buffer_Is_Empty = 0;

                GetSystemTime(&time);
                printf("%02d:%02d:%02d     ", time.wHour + 8, time.wMinute, time.wSecond);

                position = SM->buf.Buffer_End - SM->buf.Buffer_Head;
                if (position < 0)
                    position += 6;

                printf("%15dCONSUMER---READING---%s---for#%d\t", state, con, p);
                cout << endl;
                for (int d = 0; d < 10; d++)
                    cout << " ";

                for (int i = SM->buf.Buffer_Head, j = 0; j < position; j++, i++)
                    cout << SM->buf.Buf[i % Size_Of_Buffer] << "  ";
                cout << endl;
                //cout << "CONSUMER---" << state << "---READING---" << con<< "---READING---" << p << endl;
                ReleaseMutex(Temp_Mutex);
                ReleaseSemaphore(Temp_Memory_Is_Empty, 1, NULL);
            }
            UnmapViewOfFile(pFile);
            pFile = NULL;
        }

        CloseHandle(hFileMapping);
    }

    CloseHandle(Handle_Of_FileMap);
    Handle_Of_FileMap = INVALID_HANDLE_VALUE;

    system("pause");
    return 0;
}